#include <iostream>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
void Usage(string proc)
{
    cout << "Usage /n/t" << proc << "server_ip server_port" << endl;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        return 1;
    }

    // 1.创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cerr << "socker error" << errno << endl;
        return 2;
    }

    // 2.客户端需要显示bind吗？
    /*
     * a. 首先客户端也必须要有IP和PORT
     * b. 但是客户端不需要显示的bind，因为一旦bind就需要给出sockaddr_in结构体（包括地址类型、端口号、IP）
     * 正常情况下：
     * server端的端口號碼必須確定切不變；
     * client端只需要有就行，OS会在客户端发送数据时自动bind，采用随机端口的方式
     */

    // 通过main的命令行参数获得server端的IP和PORT
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(stoi(argv[2]));
    server.sin_addr.s_addr = inet_addr(argv[1]);

    // 3.使用服务
    while (1)
    {
        // a.你的数据从哪里来？
        string message;
        cout << "输入:";
        cin >> message;

        // b.你的数据到哪里去？
        sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));

        // 占位参数 tmp/len ———— recvfrom()函数要保存发送端的sockaddr 和 socklen_t
        struct sockaddr_in tmp;
        socklen_t len = sizeof(tmp);

        char buffer[1024]; // 保存server端的反馈值
        ssize_t ret = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&tmp, &len);
        if (ret > 0)
        {
            // 在网络通信过程中，只有报文大小，或者字节流中字节的个数，没有C/C++中字符串这样的概念
            buffer[ret] = 0;
            cout << "server# " << buffer << endl;
        }
        else
        {
            // TODO
        }
    }
    return 0;
}